#include "System/RTC/rtc.h"
#include <string.h>

/* 内部日期星期计算 */
static const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const uint8_t week_table[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
rtc_time_t rtc_time;

// 判断是否为闰年
static uint8_t is_leap_year(uint16_t year)
{
    if (year % 4 != 0)
        return 0;
    if (year % 100 != 0)
        return 1;
    return (year % 400 == 0);
}

// 日期转换为秒数（自1970-01-01 00:00:00起）
static uint32_t date_to_seconds(const rtc_time_t *t)
{
    uint32_t seconds = 0;

    // 年到秒
    for (uint16_t y = 1970; y < t->year; y++)
    {
        seconds += is_leap_year(y) ? 31622400 : 31536000;
    }

    // 月到秒
    for (uint8_t m = 1; m < t->month; m++)
    {
        seconds += days_in_month[m - 1] * 86400;
        if (m == 2 && is_leap_year(t->year))
            seconds += 86400;
    }

    // 日到秒
    seconds += (t->day - 1) * 86400;
    seconds += t->hour * 3600;
    seconds += t->min * 60;
    seconds += t->sec;

    return seconds;
}

// 计算星期几（1=Monday, ..., 7=Sunday）
static uint8_t calc_week(uint16_t year, uint8_t month, uint8_t day)
{
    if (month == 1 || month == 2)
    {
        month += 12;
        year--;
    }
    uint8_t q = day;
    uint8_t m = month;
    uint16_t k = year % 100;
    uint16_t j = year / 100;

    uint8_t h = (q + (13 * (m + 1)) / 5 + k + k / 4 + j / 4 + 5 * j) % 7;

    // h: 0=Saturday, 1=Sunday, ..., 6=Friday
    // 转换为我们想要的：0=Sunday, ..., 6=Saturday
    return (h + 5) % 7 + 1; // 1=Monday, ..., 7=Sunday （ISO 8601）
}

// 秒数转换为日期
static void seconds_to_date(uint32_t seconds, rtc_time_t *t)
{
    uint16_t year = 1970;
    uint32_t days = seconds / 86400;
    uint32_t remaining = seconds % 86400;

    // 年
    while (days >= (is_leap_year(year) ? 366 : 365))
    {
        days -= is_leap_year(year) ? 366 : 365;
        year++;
    }
    t->year = year;

    // 月
    uint8_t month = 1;
    while (days >= days_in_month[month - 1])
    {
        if (month == 2 && is_leap_year(year))
        {
            if (days >= 29)
                days -= 29;
            else
                break;
        }
        else
        {
            if (days >= days_in_month[month - 1])
                days -= days_in_month[month - 1];
            else
                break;
        }
        month++;
    }
    t->month = month;
    t->day = days + 1;

    // 时间
    t->hour = remaining / 3600;
    t->min = (remaining % 3600) / 60;
    t->sec = remaining % 60;

    // 星期
    uint16_t temp = t->year + t->year / 4;
    temp = temp % 7;
    temp = temp + t->day + week_table[t->month - 1];
    if (t->year % 4 == 0 && t->month < 3)
        temp--;
    t->week = t->week = calc_week(t->year, t->month, t->day);
    ;
}

/**
 * @brief   RTC 初始化
 * @param   updata: 是否更新时间（1: 是, 0: 否）
 * @retval  无
 */
void rtc_init(uint8_t updata)
{
    if (updata == 1)
    {
        RTC_SET_COUNTER(0);
    }
    rtc_get_time(&rtc_time);
}

/**
 * @brief   设置时间
 * @param   time: 时间结构体
 * @retval  无
 */
void rtc_set_time(const rtc_time_t *time)
{
    uint32_t counter = date_to_seconds(time);
    RTC_SET_COUNTER(counter);
}

/**
 * @brief   获取时间
 * @param   time: 时间结构体指针
 * @retval  无
 */
void rtc_get_time(rtc_time_t *time)
{
    uint32_t counter = RTC_GET_COUNTER();
    seconds_to_date(counter, time);
}
